<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script>
    const PENDING = 'pending',
      FULFILLED = 'fulfilled',
      REJECTED = 'rejected';
    class MyPromise {
      constructor(executor) {
        this.state = PENDING;
        this.value = undefined;
        this.reason = undefined;
        this.onResolvedCallbacks = [];
        this.onRejectedCallbacks = [];

        let resolve = (value) => {
          if (this.state === PENDING) {
            this.state = FULFILLED
            this.value = value;
            this.onResolvedCallbacks.forEach(fn => fn());
          }
        };

        let reject = (reason) => {
          if (this.state === PENDING) {
            this.state = REJECTED
            this.reason = reason;
            this.onRejectedCallbacks.forEach(fn => fn());
          }
        };

        try {
          executor(resolve, reject)
        } catch (err) {
          reject(err)
        }

      }

      then(onFulFilled, onRejected) {

        let p2 = new MyPromise((resolve, reject) => {
          let x;
          if (this.state === FULFILLED) {
            setTimeout(() => {
              x = onFulFilled(this.value)
              resolvePromise(p2, x, resolve, reject)
            }, 0);
          }

          if (this.state === REJECTED) {
            resolvePromise(p2, x, resolve, reject)
          }

          if (this.state === PENDING) {
            this.onResolvedCallbacks.push(() => {
              x = onFulFilled(this.value)
              resolvePromise(p2, x, resolve, reject)
            });
            this.onRejectedCallbacks.push(() => {
              x = onRejected(this.reason)
              resolvePromise(p2, x, resolve, reject)
            })
          }
        })

        return p2

      }
    }

    function resolvePromise(p2, x, resolve, reject) {
      if (p2 === x) {
        return new Error('引用错误')
      }
      // 返回值是thenable对象
      if (typeof x === 'object' && x !== null || typeof x === 'function') {
        try {
          let then = x.then;
          if (typeof then === 'function') {
            then.call(x,
              y => {
                resolvePromise(p2, y, resolve, reject);
              },
              err => {
                reject(err);
              });
          }
        } catch (err) {
          reject(err)
        }
      } else {
        resolve(x)
      }
    }

    function test() {
      return new MyPromise((resolve, reject) => {
        setTimeout(() => {
          resolve(100)
        }, 1000)
      })
    }

    let p = test()

    var p2 = p.then((res) => {
      // return {
      //   then(resolve, reject) {
      //     resolve(100000)
      //   }
      // }
      // console.log(res);

      return new MyPromise((resolve, reject) => {
        resolve(
          new Promise((resolve, reject) => {
            resolve(10000000000)
          })
        )
      })
    }, err => {
      console.log(err);
    })

    p2.then(res => {
      console.log(res);
    })
  </script>
</body>

</html>